﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
using System.Reflection.Emit;

namespace Qianwei.Common
{
    /// <summary>
    /// Mapper转换
    /// </summary>
    public class Mapper
    {
        /// <summary>
        /// DataReader转换为实体
        /// </summary>
        /// <typeparam name="T">转换的类型</typeparam>
        /// <param name="reader">DataReader对象</param>
        /// <returns></returns>
        public static T DataReaderToObject<T>(IDataReader reader) where T : new()
        {
            T obj = default(T);
            if (reader == null) return obj;
            DynamicBuilder<T> builder = DynamicBuilder<T>.CreateBuilder(reader);
            while (reader.Read())
            {
                obj = builder.Build(reader);
            }
            reader.Close();
            reader.Dispose();
            return obj;
        }

        /// <summary>
        /// DataReader转换为list
        /// </summary>
        /// <typeparam name="T">要转换的类型</typeparam>
        /// <param name="reader">DataReader对象</param>
        /// <returns></returns>
        public static IList<T> DataReaderToList<T>(IDataReader reader) where T : new()
        {
            IList<T> list = new List<T>();
            if (reader == null) return list;
            DynamicBuilder<T> builder = DynamicBuilder<T>.CreateBuilder(reader);
            while (reader.Read())
            {
                list.Add(builder.Build(reader));
            }
            reader.Close();
            reader.Dispose();
            return list;
        }

        /// <summary>
        /// 转换DataRow到指定类型的对象
        /// </summary>
        public static T DataRowToObject<T>(DataRow row) where T : new()
        {
            T obj = new T();
            // 如果row为空，则返回null对象
            if (row == null)
            {
                return obj;
            }
            
            // 遍历各个数据列给对象赋值（这样更为合理，以防止对象有附加的只读或计算属性）
            Type dataType = obj.GetType();
            foreach (DataColumn column in row.Table.Columns)
            {
                string field = column.ColumnName;
                object ovalue = row[field];
                //PropertyInfo p = dataType.GetProperty(field.Replace("_", ""), BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                PropertyInfo p = dataType.GetProperty(field, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                if (p != null && p.CanWrite)
                {
                    if (row[field] != DBNull.Value && row[field].GetType() != typeof(DBNull))
                        p.SetValue(obj, row[field], null);
                    else
                        p.SetValue(obj, null, null);
                }
            }
            return obj;
        }

        /// <summary>
        /// 转换DataTable到List列表
        /// </summary>
        public static IList<T> DataTableToObject<T>(DataTable table) where T : new()
        {
            List<T> lst = new List<T>();
            if (table == null) return lst;
            foreach (DataRow row in table.Rows)
            {
                lst.Add(DataRowToObject<T>(row));
            }
            return lst;
        }
    }

    public class DynamicBuilder<T>
    {
        private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });
        private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
        private delegate T Load(IDataRecord dataRecord);
        private Load handler;

        private DynamicBuilder() { }

        public T Build(IDataRecord dataRecord)
        {
            return handler(dataRecord);
        }

        public static DynamicBuilder<T> CreateBuilder(IDataRecord dataRecord)
        {
            DynamicBuilder<T> dynamicBuilder = new DynamicBuilder<T>();

            DynamicMethod method = new DynamicMethod("DynamicCreate", typeof(T), new Type[] { typeof(IDataRecord) }, typeof(T), true);
            ILGenerator generator = method.GetILGenerator();

            LocalBuilder result = generator.DeclareLocal(typeof(T));
            generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
            generator.Emit(OpCodes.Stloc, result);

            for (int i = 0; i < dataRecord.FieldCount; i++)
            {
                //PropertyInfo propertyInfo = typeof(T).GetProperty(dataRecord.GetName(i).Replace("_",""), BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                PropertyInfo propertyInfo = typeof(T).GetProperty(dataRecord.GetName(i), BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                Label endIfLabel = generator.DefineLabel();

                if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
                {
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, isDBNullMethod);
                    generator.Emit(OpCodes.Brtrue, endIfLabel);

                    generator.Emit(OpCodes.Ldloc, result);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, getValueMethod);
                    generator.Emit(OpCodes.Unbox_Any, dataRecord.GetFieldType(i));
                    generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());

                    generator.MarkLabel(endIfLabel);
                }
            }

            generator.Emit(OpCodes.Ldloc, result);
            generator.Emit(OpCodes.Ret);

            dynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
            return dynamicBuilder;
        }
    }
}
